import asyncio
import json
from asyncio import Transport
from typing import List, Dict
import socketserver

from Lib import Lang_Zh, Utils
from Lib.Message import MessageSync
from Lib.Utils import Console
from Proto import Proto


class TcpRequestHandler(socketserver.BaseRequestHandler):
    def __init__(self, request, client_address, server):
        super().__init__(request, client_address, server)
        self.user_id = 0
        self.ip = ""
        self.port = 0
        self.token = ""
        self.nickname = ""
        self.device = ""

    def handle(self):
        try:
            while True:
                payload = self.request.recv(1024)
                if payload:
                    self.onMessage(payload)
        except Exception as e:
            Utils.Console(Lang_Zh.CLIENT_ABNORMAL_LEAVE_SERVER.format(self.client_address, e), "error", color=7)
        finally:
            self.request.close()

    def setup(self):
        Utils.Console(Lang_Zh.CLIENT_ENTER_SERVER.format(self.client_address), "info", color=46)

    def finish(self):
        Utils.Console(Lang_Zh.CLIENT_LEAVE_SERVER.format(self.client_address), "info", color=27)
        import locals
        locals.RemoveDevice(self.user_id, self.device)

    def onMessage(self, payload):
        Utils.Console(Lang_Zh.CLIENT_RIVE_MESSAGE.format(payload))
        message_event = json.loads(payload)
        header = message_event['header']
        data = message_event['data']
        send_time = message_event['send_time']
        proto = header['proto']
        self.device = header['device']
        if proto == Proto.USER_LOGIN.value:
            self.user_id = data['user_id']
            self.token = header['token']
            import locals
            locals.AddDevice(self.client_address, self.device, self.user_id, self.token)


class UdpProtocol(asyncio.Protocol):
    def __init__(self):
        self.transport = None

    def connection_made(self, transport: Transport) -> None:
        self.transport = transport

    def datagram_received(self, data: bytes, addr, args=None) -> None:
        message = data.decode()
        print('Received %r from %s' % (message, addr))
        print('Send %r to %s' % (message, addr))
        self.transport.sendto(data, addr)


class Server:
    def __init__(self, config):
        self.loop = asyncio.get_event_loop()
        self.list_client: List = []
        self.host = config.get("base", "host")
        self.port = int(config.get("base", "tcp_port"))
        self.dict_room_server: Dict = {}
        self.list_sync: List[MessageSync] = []
        self.list_udp_port: List[int] = Utils.GeneratorIntList(int(config.get('base', 'udp_port_min')),
                                                               int(config.get('base', 'udp_port_max')))

    def GetOnlyUdpPort(self) -> [bool, int]:
        import random
        if len(self.list_udp_port) > 0:
            port = random.choice(self.list_udp_port)
            self.list_udp_port.remove(port)
            return port
        else:
            return False

    def CreateUdpServer(self, room_uuid, host, port):
        udp = self.loop.create_datagram_endpoint(UdpProtocol, (host, port))
        Console(f"正在启动 UDP 服务 :::===>>> {host} : {port}", "info", start="")
        Console(f"剩余可用 UDP 端口数 :: {len(self.list_udp_port)} 个", "info")
        self.dict_room_server[room_uuid] = udp
        self.loop.create_task(udp)
        return udp, (host, port)


config = Utils.GetIniFile("./config.ini")
server = Server(config)
